#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
房型床位数据导出器
从MongoDB导出房型床位数据到CSV文件
"""

import csv
import os
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional
from pymongo import MongoClient
from bson.objectid import ObjectId
from config import ROOM_MONGODB_CONFIG, ROOM_EXPORT_CONFIG, ROOM_CSV_HEADERS
from progress_manager import ProgressManager


class RoomBedTypeExporter:
    """房型床位数据导出器"""
    
    def __init__(self):
        self.config = ROOM_MONGODB_CONFIG
        self.export_config = ROOM_EXPORT_CONFIG
        self.null_placeholder = ROOM_EXPORT_CONFIG['null_placeholder']
        self.client = None
        self.db = None
        self.collection = None
        
        # 初始化日志
        self._setup_logging()
        
        # 初始化输出目录
        self._setup_output_dir()
        
        # CSV文件路径
        self.csv_paths = {
            'basic_bed': os.path.join(
                self.export_config['output_dir'],
                self.export_config['csv_files']['basic_bed']
            ),
            'complex_bed': os.path.join(
                self.export_config['output_dir'],
                self.export_config['csv_files']['complex_bed']
            )
        }
        
        # 数据缓冲区
        self.buffers = {
            'basic_bed': [],
            'complex_bed': []
        }
        
        # 统计信息
        self.stats = {
            'total_rooms': 0,
            'processed_rooms': 0,
            'basic_bed_rows': 0,
            'complex_bed_rows': 0,
            'error_count': 0
        }
        
        # 进度管理器（独立的session_name，不与设施导出冲突）
        self.progress_manager = ProgressManager(
            progress_dir=self.export_config.get('progress_dir', 'progress'),
            session_name='room_bed_export'
        )
    
    def _setup_logging(self):
        """设置日志"""
        log_dir = self.export_config['log_dir']
        os.makedirs(log_dir, exist_ok=True)
        
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        log_file = os.path.join(log_dir, f'room_export_{timestamp}.log')
        
        # 文件日志 - 记录详细信息
        file_handler = logging.FileHandler(log_file, encoding='utf-8')
        file_handler.setLevel(logging.DEBUG)
        file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
        
        # 控制台日志 - 只显示重要信息
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.WARNING)  # 只显示警告和错误
        console_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
        
        # 配置logger
        self.logger = logging.getLogger(__name__ + '_room')
        self.logger.setLevel(logging.DEBUG)
        self.logger.addHandler(file_handler)
        self.logger.addHandler(console_handler)
    
    def _setup_output_dir(self):
        """创建输出目录"""
        output_dir = self.export_config['output_dir']
        os.makedirs(output_dir, exist_ok=True)
    
    def connect_mongodb(self):
        """连接MongoDB"""
        try:
            self.logger.info("正在连接MongoDB...")
            self.client = MongoClient(
                host=self.config['host'],
                port=self.config['port'],
                username=self.config['username'],
                password=self.config['password']
            )
            
            # 测试连接
            self.client.server_info()
            
            # 获取数据库和集合
            self.db = self.client[self.config['db_name']]
            self.collection = self.db[self.config['collection_name']]
            
            self.logger.info(f"MongoDB连接成功")
            self.logger.info(f"数据库: {self.config['db_name']}")
            self.logger.info(f"集合: {self.config['collection_name']}")
            
            return True
        except Exception as e:
            self.logger.error(f"MongoDB连接失败: {str(e)}")
            return False
    
    def disconnect_mongodb(self):
        """断开MongoDB连接"""
        if self.client:
            self.client.close()
            self.logger.info("MongoDB连接已关闭")
    
    def _get_value(self, data: Any, default: str = None) -> str:
        """安全获取值，处理空值"""
        if default is None:
            default = self.null_placeholder
        
        if data is None or data == '':
            return default
        return str(data)
    
    def _process_basic_bed_types(self, room_doc: Dict) -> List[List[str]]:
        """
        处理基本床型信息
        返回CSV行列表
        """
        rows = []
        
        # 获取基本信息
        doc_id = self._get_value(room_doc.get('_id'))
        raw_data = room_doc.get('rawData', {})
        
        room_id = self._get_value(raw_data.get('roomID'))
        room_name = self._get_value(raw_data.get('roomName'))
        person = self._get_value(raw_data.get('person'))
        has_window = self._get_value(raw_data.get('hasWindow'))
        add_bed_fee = self._get_value(raw_data.get('addBedFee'))
        area_range = self._get_value(raw_data.get('areaRange'))
        floor_range = self._get_value(raw_data.get('floorRange'))
        
        # 获取基本床型配置
        basic_room_bed_types = raw_data.get('basicRoomBedTypes', [])
        
        if not basic_room_bed_types or not isinstance(basic_room_bed_types, list):
            # 没有床型数据，生成一行空床型数据
            rows.append([
                doc_id, room_id, room_name, person, has_window, add_bed_fee,
                area_range, floor_range,
                self.null_placeholder,  # 基本床型ID
                self.null_placeholder,  # 基本床的数量
                self.null_placeholder   # 基本床的宽度
            ])
        else:
            # 穷举每种床型配置
            for bed_type in basic_room_bed_types:
                child_bed_type_id = self._get_value(bed_type.get('childBedTypeID'))
                bed_count = self._get_value(bed_type.get('bedCount'))
                bed_width = self._get_value(bed_type.get('bedWidth'))
                
                rows.append([
                    doc_id, room_id, room_name, person, has_window, add_bed_fee,
                    area_range, floor_range,
                    child_bed_type_id, bed_count, bed_width
                ])
        
        return rows
    
    def _process_complex_bed_types(self, room_doc: Dict) -> List[List[str]]:
        """
        处理复杂床型信息
        返回CSV行列表
        """
        rows = []
        
        # 获取_id
        doc_id = self._get_value(room_doc.get('_id'))
        
        # 获取rawData
        raw_data = room_doc.get('rawData', {})
        
        # 获取physicalBedInfo
        physical_bed_info = raw_data.get('physicalBedInfo', {})
        complicated_bed_info = physical_bed_info.get('complicatedBedInfo', {})
        room_bed_info_list = complicated_bed_info.get('roomBedInfoList')
        
        # 检查是否有复杂床型数据
        if not room_bed_info_list or not isinstance(room_bed_info_list, list):
            # 没有复杂床型数据，不生成行（或者可以选择生成一行空数据）
            return rows
        
        # 穷举每个卧室的每种床型
        for room_info in room_bed_info_list:
            room_name = self._get_value(room_info.get('roomName'))
            room_type = self._get_value(room_info.get('roomType'))
            
            # 获取床组列表
            bed_group_list = room_info.get('bedGroupList', [])
            
            if not bed_group_list or not isinstance(bed_group_list, list):
                continue
            
            # 遍历每个床组
            for bed_group in bed_group_list:
                sub_bed_info_list = bed_group.get('subBedInfoList', [])
                
                if not sub_bed_info_list or not isinstance(sub_bed_info_list, list):
                    continue
                
                # 遍历每个子床型
                for sub_bed in sub_bed_info_list:
                    bed_id = self._get_value(sub_bed.get('bedId'))
                    bed_name = self._get_value(sub_bed.get('bedName'))
                    bed_count = self._get_value(sub_bed.get('bedCount'))
                    bed_width = self._get_value(sub_bed.get('bedWidth'))
                    
                    # 获取床宽度范围信息
                    bed_width_range_info = sub_bed.get('bedWidthRangeInfo', {})
                    if isinstance(bed_width_range_info, dict):
                        max_value = self._get_value(bed_width_range_info.get('maxValue'))
                        min_value = self._get_value(bed_width_range_info.get('minValue'))
                        unit = self._get_value(bed_width_range_info.get('unit'))
                        bed_width_desc = self._get_value(bed_width_range_info.get('bedWidthDesc'))
                    else:
                        max_value = self.null_placeholder
                        min_value = self.null_placeholder
                        unit = self.null_placeholder
                        bed_width_desc = self.null_placeholder
                    
                    rows.append([
                        doc_id, room_name, room_type, bed_id, bed_name, bed_count,
                        bed_width, max_value, min_value, unit, bed_width_desc
                    ])
        
        return rows
    
    def _write_buffer_to_csv(self, csv_type: str, force: bool = False):
        """
        将缓冲区数据写入CSV文件
        
        Args:
            csv_type: CSV类型 ('basic_bed' 或 'complex_bed')
            force: 是否强制写入（不管缓冲区大小）
        """
        buffer = self.buffers[csv_type]
        write_buffer_size = self.export_config['write_buffer_size']
        
        # 如果缓冲区数据量达到阈值或强制写入
        if len(buffer) >= write_buffer_size or (force and len(buffer) > 0):
            csv_path = self.csv_paths[csv_type]
            
            # 判断文件是否存在（决定是否写表头）
            file_exists = os.path.exists(csv_path)
            
            try:
                with open(csv_path, 'a', newline='', encoding='utf-8-sig') as f:
                    writer = csv.writer(f)
                    
                    # 如果是新文件，先写表头
                    if not file_exists:
                        writer.writerow(ROOM_CSV_HEADERS[csv_type])
                    
                    # 写入数据
                    writer.writerows(buffer)
                
                # 更新统计
                if csv_type == 'basic_bed':
                    self.stats['basic_bed_rows'] += len(buffer)
                else:
                    self.stats['complex_bed_rows'] += len(buffer)
                
                self.logger.debug(f"已写入 {len(buffer)} 行数据到 {csv_type}")
                
                # 清空缓冲区
                buffer.clear()
                
            except Exception as e:
                self.logger.error(f"写入CSV文件失败 ({csv_type}): {str(e)}")
                raise
    
    def _process_room(self, room_doc: Dict):
        """处理单个房型文档"""
        try:
            # 处理基本床型信息
            basic_bed_rows = self._process_basic_bed_types(room_doc)
            self.buffers['basic_bed'].extend(basic_bed_rows)
            
            # 处理复杂床型信息
            complex_bed_rows = self._process_complex_bed_types(room_doc)
            self.buffers['complex_bed'].extend(complex_bed_rows)
            
            # 检查是否需要写入文件
            self._write_buffer_to_csv('basic_bed', force=False)
            self._write_buffer_to_csv('complex_bed', force=False)
            
        except Exception as e:
            self.logger.error(f"处理房型失败 (_id: {room_doc.get('_id')}): {str(e)}")
            self.stats['error_count'] += 1
            # 记录错误到进度管理器
            self.progress_manager.log_error(
                hotel_id=str(room_doc.get('_id')),
                error_type='processing_error',
                error_message=str(e)
            )
    
    def export(self) -> bool:
        """执行导出"""
        try:
            print("\n" + "=" * 70)
            print("开始导出房型床位数据")
            print("=" * 70)
            
            # 连接数据库
            if not self.connect_mongodb():
                return False
            
            # 获取总数（快速估算）
            self.logger.info("正在统计房型总数...")
            self.stats['total_rooms'] = self.collection.estimated_document_count()
            self.logger.info(f"房型总数（估算）: {self.stats['total_rooms']}")
            
            # 应用测试限制
            test_limit = self.export_config.get('test_limit')
            if test_limit:
                print(f"\n[TEST MODE] 测试模式：仅处理 {test_limit} 条房型数据")
                self.logger.info(f"测试模式：限制处理 {test_limit} 条房型")
            
            # 检查是否启用断点续传
            enable_resume = self.export_config.get('enable_resume', True)
            last_id = None
            
            if enable_resume:
                has_progress = self.progress_manager.load_progress()
                if has_progress:
                    last_id = self.progress_manager.get_last_processed_id()
                    if last_id:
                        self.stats['processed_rooms'] = self.progress_manager.get_processed_count()
                        # 注意：ProgressManager使用的字段名是 basic_facility_rows/facility_group_rows
                        # 这里我们复用这些字段存储房型的统计数据
                        self.stats['basic_bed_rows'] = self.progress_manager.progress_data.get('basic_facility_rows', 0)
                        self.stats['complex_bed_rows'] = self.progress_manager.progress_data.get('facility_group_rows', 0)
                        self.stats['error_count'] = self.progress_manager.progress_data.get('error_count', 0)
                        
                        print(f"\n[RESUME] 检测到上次进度，从 _id={last_id} 继续")
                        self.logger.info(f"断点续传：从 _id={last_id} 继续处理")
            
            # 构建查询条件
            query = {}
            if last_id:
                query['_id'] = {'$gt': last_id}
            
            # 批量读取并处理
            batch_size = self.export_config['batch_size']
            progress_save_interval = self.export_config['progress_save_interval']
            
            print(f"\n开始处理房型数据...")
            print(f"批量大小: {batch_size}")
            print(f"进度保存间隔: 每 {progress_save_interval} 条")
            print("-" * 70)
            
            cursor = self.collection.find(query).sort('_id', 1).batch_size(batch_size)
            
            if test_limit:
                cursor = cursor.limit(test_limit)
            
            processed_count = 0
            for room_doc in cursor:
                # 处理房型
                self._process_room(room_doc)
                
                processed_count += 1
                self.stats['processed_rooms'] += 1
                
                # 定期保存进度
                if processed_count % progress_save_interval == 0:
                    # 先刷新缓冲区
                    self._write_buffer_to_csv('basic_bed', force=True)
                    self._write_buffer_to_csv('complex_bed', force=True)
                    
                    # 保存进度（注意：复用ProgressManager的字段名）
                    self.progress_manager.save_progress(
                        last_processed_id=str(room_doc['_id']),
                        processed_count=self.stats['processed_rooms'],
                        basic_facility_rows=self.stats['basic_bed_rows'],
                        facility_group_rows=self.stats['complex_bed_rows'],
                        error_count=self.stats['error_count']
                    )
                    
                    # 显示进度
                    print(f"已处理: {self.stats['processed_rooms']} 条 | "
                          f"基本床型: {self.stats['basic_bed_rows']} 行 | "
                          f"复杂床型: {self.stats['complex_bed_rows']} 行 | "
                          f"错误: {self.stats['error_count']}")
            
            # 写入剩余的缓冲区数据
            self._write_buffer_to_csv('basic_bed', force=True)
            self._write_buffer_to_csv('complex_bed', force=True)
            
            # 保存最终进度
            if processed_count > 0:
                self.progress_manager.save_progress(
                    last_processed_id='COMPLETED',
                    processed_count=self.stats['processed_rooms'],
                    basic_facility_rows=self.stats['basic_bed_rows'],
                    facility_group_rows=self.stats['complex_bed_rows'],
                    error_count=self.stats['error_count']
                )
            
            # 断开数据库连接
            self.disconnect_mongodb()
            
            # 显示最终结果
            print("\n" + "=" * 70)
            print("导出完成！")
            print("=" * 70)
            print(f"处理房型数: {self.stats['processed_rooms']}")
            print(f"基本床型信息行数: {self.stats['basic_bed_rows']}")
            print(f"复杂床型信息行数: {self.stats['complex_bed_rows']}")
            print(f"错误数量: {self.stats['error_count']}")
            print(f"\n输出文件:")
            print(f"  - {self.csv_paths['basic_bed']}")
            print(f"  - {self.csv_paths['complex_bed']}")
            print("=" * 70)
            
            self.logger.info("导出完成")
            self.logger.info(f"统计信息: {self.stats}")
            
            return True
            
        except KeyboardInterrupt:
            print("\n\n[INTERRUPT] 用户中断！正在保存进度...")
            self.logger.warning("用户中断导出")
            
            # 保存缓冲区数据
            try:
                self._write_buffer_to_csv('basic_bed', force=True)
                self._write_buffer_to_csv('complex_bed', force=True)
                print("[OK] 已保存缓冲区数据")
            except Exception as e:
                print(f"[ERROR] 保存缓冲区失败: {str(e)}")
            
            self.disconnect_mongodb()
            print("[OK] 进度已保存，下次运行将从此处继续")
            return False
            
        except Exception as e:
            self.logger.error(f"导出过程发生错误: {str(e)}", exc_info=True)
            self.disconnect_mongodb()
            return False

